# -*- coding:utf-8 -*-
import threading

from pymongo import MongoClient

from pyspider.libs.utils import md5string

default_mongo_key = ['connect', 'maxPoolSize', 'maxIdleTimeMS', 'appname']


class SingletonMongoClient(MongoClient):
    """
    MongoClient 单例模式
    """
    _instance_lock = threading.Lock()

    def __new__(cls, uri, **kwargs):
        singleton_instance_key = cls.singleton_instance_key(uri, **kwargs)
        if not hasattr(SingletonMongoClient, singleton_instance_key):
            with SingletonMongoClient._instance_lock:
                if not hasattr(SingletonMongoClient, singleton_instance_key):
                    setattr(SingletonMongoClient, singleton_instance_key, MongoClient(uri, **kwargs))
        return getattr(SingletonMongoClient, singleton_instance_key)

    @staticmethod
    def singleton_instance_key(uri, **kwargs):
        """
        相同参数生成唯一实例
        :param uri:
        :param kwargs:
        :return:
        """
        unique_key = uri
        for key in sorted(kwargs.keys()):
            unique_key += '{}_{}'.format(key, kwargs[key])
        unique_key = md5string(unique_key)
        return '_singleton_instance_{}'.format(unique_key)


class MongoBase(object):
    """
    mongo 连接基类
    """

    def __init__(self, uri, database=None, collection=None, **kwargs):
        for default_key in default_mongo_key:
            if default_key in kwargs:
                kwargs.pop(default_key)
        appname = 'spider_{}_{}'.format(md5string(uri), database)
        self.conn = SingletonMongoClient(uri, connect=False, appname=appname, maxPoolSize=5000, maxIdleTimeMS=1000,
                                         **kwargs)
        self._database = database
        self._collection = collection

    @property
    def db(self):
        """
        获取库链接
        :return:
        """
        if self._database and isinstance(self._database, str):
            return self.conn[self._database]

    @property
    def col(self):
        """
        获取表链接
        :return:
        """
        if self._collection and isinstance(self._collection, str):
            return self.db[self._collection]
